﻿using System.Text;
using Basic.FlowRemoteModel;
using Basic.FlowRemoteModel.FlowNode.Model;
using Basic.FormRemoteModel;
using Basic.FormRemoteModel.QueryInter.Model;
using Flee.PublicTypes;
using WeDonekRpc.Helper;

namespace Basic.FlowApplication.Linq
{
    internal static class FormulaLinq
    {
        public static bool IsOk ( this FilterFormula[] items, Dictionary<long, FormVal> vals )
        {
            if ( vals.Count == 0 )
            {
                return false;
            }
            else if ( items.Length == 1 )
            {
                return _CheckFormula(items[0], vals);
            }
            StringBuilder str = new StringBuilder();
            ExpressionContext exp = new ExpressionContext();
            items.ForEach(( a, i ) =>
           {
               string key = i < 26 ? PublicDataDic.Letter[i] : PublicDataDic.Letter[i] + ( i / 26 ).ToString();
               if ( i == 0 && a.IsAnd == false )
               {
                   _ = str.AppendFormat("({0} or ", key);
               }
               else if ( i != 0 && a.IsAnd && items[i - 1].IsAnd == false )
               {
                   _ = str.AppendFormat("{0}) and ", key);
               }
               else if ( a.IsAnd )
               {
                   _ = str.AppendFormat("{0} and ", key);
               }
               else
               {
                   _ = str.AppendFormat("{0} or ", key);
               }
               bool res = _CheckFormula(a, vals);
               exp.Variables.Add(key, res);
           });
            _ = str.Remove(str.Length - 4, 4);
            if ( !items[^1].IsAnd )
            {
                _ = str.Append(")");
            }
            IDynamicExpression dyna = exp.CompileDynamic(str.ToString());
            return (bool)dyna.Evaluate();
        }
        private static bool _CheckFormula ( FilterFormula a, Dictionary<long, FormVal> vals )
        {
            if ( vals.TryGetValue(a.ColId, out FormVal val) )
            {
                if ( val.DataType == FormRecordDataType.Array )
                {
                    return _CheckArray(a, val.Vals);
                }
                else if ( val.DataType == FormRecordDataType.Date || val.DataType == FormRecordDataType.DateTime )
                {
                    return _CheckDateTime(a, val.LongVal.HasValue ? val.LongVal.Value.ToDateTime() : null);
                }
                else if ( val.DataType == FormRecordDataType.Number )
                {
                    return _CheckNumber(a, val.NumVal);
                }
                else if ( val.DataType == FormRecordDataType.Long )
                {
                    return _CheckLong(a, val.LongVal);
                }
                else if ( val.DataType == FormRecordDataType.Time )
                {
                    return _CheckTime(a, val.LongVal);
                }
                else if ( val.DataType == FormRecordDataType.Bool )
                {
                    return _CheckBool(a, val.BoolVal);
                }
                else
                {
                    return _CheckStr(a, val.StrVal);
                }
            }
            return false;
        }
        private static bool _CheckBool ( FilterFormula formula, bool? val )
        {
            if ( formula.Val.IsNull() && val.HasValue == false )
            {
                return true;
            }
            else if ( formula.Val.IsNull() || val.HasValue == false )
            {
                return false;
            }
            if ( formula.Con == FlowFormulaCondition.等于 )
            {
                return bool.Parse(formula.Val) == val;
            }
            else
            {
                return bool.Parse(formula.Val) != val;
            }
        }
        private static bool _CheckTime ( FilterFormula formula, long? val )
        {
            if ( formula.Val.IsNull() && !val.HasValue )
            {
                return true;
            }
            else if ( formula.Val.IsNull() || !val.HasValue )
            {
                return false;
            }
            long left = val.Value;
            if ( formula.Con == FlowFormulaCondition.包含 )
            {
                long[] rights = formula.Vals.ConvertAll(long.Parse);
                return rights.Contains(left);
            }
            else if ( formula.Con == FlowFormulaCondition.不包含 )
            {
                long[] rights = formula.Vals.ConvertAll(long.Parse);
                return !rights.Contains(left);
            }
            int index = formula.Val.IndexOf(':');
            long right = ( long.Parse(formula.Val.Substring(0, index)) * 60 ) + long.Parse(formula.Val.Substring(index + 1));
            if ( formula.Con == FlowFormulaCondition.等于 )
            {
                return left == right;
            }
            else if ( formula.Con == FlowFormulaCondition.小于 )
            {
                return left < right;
            }
            else if ( formula.Con == FlowFormulaCondition.大于 )
            {
                return left > right;
            }
            else if ( formula.Con == FlowFormulaCondition.大于等于 )
            {
                return left >= right;
            }
            else if ( formula.Con == FlowFormulaCondition.小于等于 )
            {
                return left <= right;
            }
            else
            {
                return left != right;
            }
        }
        private static bool _CheckStr ( FilterFormula formula, string val )
        {
            if ( formula.Val.IsNull() && val.IsNull() )
            {
                return true;
            }
            else if ( formula.Val.IsNull() || val.IsNull() )
            {
                return false;
            }
            if ( formula.Con == FlowFormulaCondition.包含 )
            {
                return formula.Vals.Contains(val);
            }
            else if ( formula.Con == FlowFormulaCondition.不包含 )
            {
                return !formula.Vals.Contains(val);
            }
            if ( formula.Con == FlowFormulaCondition.等于 )
            {
                return formula.Val == val;
            }
            else
            {
                return formula.Val != val;
            }
        }
        private static bool _CheckLong ( FilterFormula formula, long? val )
        {
            if ( formula.Val.IsNull() && !val.HasValue )
            {
                return true;
            }
            else if ( formula.Val.IsNull() || !val.HasValue )
            {
                return false;
            }
            long left = val.Value;
            if ( formula.Con == FlowFormulaCondition.包含 )
            {
                long[] rights = formula.Vals.ConvertAll(long.Parse);
                return rights.Contains(left);
            }
            else if ( formula.Con == FlowFormulaCondition.不包含 )
            {
                long[] rights = formula.Vals.ConvertAll(long.Parse);
                return !rights.Contains(left);
            }
            long right = long.Parse(formula.Val);
            if ( formula.Con == FlowFormulaCondition.等于 )
            {
                return left == right;
            }
            else if ( formula.Con == FlowFormulaCondition.小于 )
            {
                return left < right;
            }
            else if ( formula.Con == FlowFormulaCondition.大于 )
            {
                return left > right;
            }
            else if ( formula.Con == FlowFormulaCondition.大于等于 )
            {
                return left >= right;
            }
            else if ( formula.Con == FlowFormulaCondition.小于等于 )
            {
                return left <= right;
            }
            else
            {
                return left != right;
            }
        }
        private static bool _CheckNumber ( FilterFormula formula, decimal? val )
        {
            if ( formula.Val.IsNull() && !val.HasValue )
            {
                return true;
            }
            else if ( formula.Val.IsNull() || !val.HasValue )
            {
                return false;
            }
            decimal left = val.Value;
            if ( formula.Con == FlowFormulaCondition.包含 )
            {
                decimal[] rights = formula.Vals.ConvertAll(decimal.Parse);
                return rights.Contains(left);
            }
            else if ( formula.Con == FlowFormulaCondition.不包含 )
            {
                decimal[] rights = formula.Vals.ConvertAll(decimal.Parse);
                return !rights.Contains(left);
            }
            decimal right = decimal.Parse(formula.Val);
            if ( formula.Con == FlowFormulaCondition.等于 )
            {
                return left == right;
            }
            else if ( formula.Con == FlowFormulaCondition.小于 )
            {
                return left < right;
            }
            else if ( formula.Con == FlowFormulaCondition.大于 )
            {
                return left > right;
            }
            else if ( formula.Con == FlowFormulaCondition.大于等于 )
            {
                return left >= right;
            }
            else if ( formula.Con == FlowFormulaCondition.小于等于 )
            {
                return left <= right;
            }
            else
            {
                return left != right;
            }
        }
        private static bool _CheckDateTime ( FilterFormula formula, DateTime? val )
        {
            if ( formula.Val.IsNull() && !val.HasValue )
            {
                return true;
            }
            else if ( formula.Val.IsNull() || !val.HasValue )
            {
                return false;
            }
            DateTime left = val.Value;
            if ( formula.Con == FlowFormulaCondition.包含 )
            {
                DateTime[] rights = formula.Vals.ConvertAll(DateTime.Parse);
                return rights.Contains(left);
            }
            else if ( formula.Con == FlowFormulaCondition.不包含 )
            {
                DateTime[] rights = formula.Vals.ConvertAll(DateTime.Parse);
                return !rights.Contains(left);
            }
            DateTime right = DateTime.Parse(formula.Val);
            if ( formula.Con == FlowFormulaCondition.等于 )
            {
                return left == right;
            }
            else if ( formula.Con == FlowFormulaCondition.小于 )
            {
                return left < right;
            }
            else if ( formula.Con == FlowFormulaCondition.大于 )
            {
                return left > right;
            }
            else if ( formula.Con == FlowFormulaCondition.大于等于 )
            {
                return left >= right;
            }
            else if ( formula.Con == FlowFormulaCondition.小于等于 )
            {
                return left <= right;
            }
            else
            {
                return left != right;
            }
        }
        private static bool _CheckArray ( FilterFormula formula, string[] vals )
        {
            if ( vals.IsNull() && formula.Vals.IsNull() )
            {
                return true;
            }
            else if ( vals.IsNull() || formula.Vals.IsNull() )
            {
                return false;
            }
            else if ( formula.Con == FlowFormulaCondition.包含 )
            {
                return vals.Any(c => formula.Vals.Contains(c));
            }
            else
            {
                return !formula.Vals.Any(vals.Contains);
            }
        }
    }
}
